/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo All rights
 * reserved.
 */
package ac.jp.u_tokyo.SyncLib.util;

import static org.junit.Assert.assertEquals;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

import ac.jp.u_tokyo.SyncLib.Mod;
import ac.jp.u_tokyo.SyncLib.NullMod;
import ac.jp.u_tokyo.SyncLib.PrimMod;

public class Helper
{
	
	public static String toString(Object[] array) {
		if (array.length < 1) return "";
		StringBuffer result = new StringBuffer();
		result.append(array[0]);
		for (int i = 1; i < array.length; i++) {
			result.append(",");
			result.append(array[i]);
		}
		return result.toString();
	}
	
	public static String toString(Object obj) {
		if (obj == null) return "null";
		else return obj.toString();
	}
	public static Object deepCopy(Object orig) {
        Object obj = null;
        try {
            // Write the object out to a byte array
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bos);
            out.writeObject(orig);
            out.flush();
            out.close();

            // Make an input stream from the byte array and read
            // a copy of the object back in.
            ObjectInputStream in = new ObjectInputStream(
                new ByteArrayInputStream(bos.toByteArray()));
            obj = in.readObject();
        }
        catch(IOException e) {
            e.printStackTrace();
        }
        catch(ClassNotFoundException cnfe) {
            cnfe.printStackTrace();
        }
        return obj;
    }

	public static <T> ArrayList<T> toArrayList(T... objs)
	{
		ArrayList<T> result = new ArrayList<T>(objs.length);
		for (int i = 0; i < objs.length; i++)
			result.add(objs[i]);
		return result;
	}

	@SuppressWarnings("unchecked")
	public static void assertPrimitiveModList(Mod[] modList, Object... values)
	{
		assertEquals(values.length, modList.length);
		for (int i = 0; i < values.length; i++) {
			if (values[i] == null)
				assert (modList[i] instanceof NullMod);
			else
				assertEquals(values[i], ((PrimMod<Object>) modList[i])
						.getNewValue());
		}
	}

	@SuppressWarnings("unchecked")
	public static Mod[] createPrimitiveModList(Object... values)
	{
		Mod[] modList = new Mod[values.length];
		for (int i = 0; i < values.length; i++)
		{
			if (values[i] != null)
				modList[i] = new PrimMod(values[i]);
			else
				modList[i] = NullMod.INSTANCE;
		}
		return modList;
	}

	public static <T> boolean areEqual(T a, T b)
	{
		if (a == null)
			return b == null;
		else
			return a.equals(b);
	}

	public static <T> Mod<T> merge(Mod<T> former, Mod<T> latter)
	{
		if (former == null)
			return latter;
		else {
			return former.merge(latter);
		}
	}

	public static <T> boolean conflict(Mod<T> mod1, Mod<T> mod2)
	{
		if (mod1 == null)
			return false;
		else
			return mod1.isConflict(mod2);
	}

	public static <T> T apply(Mod<T> mod, T v)
	{
		if (mod == null)
			return v;
		else
			return mod.apply(v);
	}

	public static <T> T inPlaceApply(Mod<T> mod, T v)
	{
		if (mod == null)
			return v;
		else
			return mod.inPlaceApply(v);
	}

	public static <T> Mod<T> getInverse(Mod<T> mod, T v)
	{
		if (mod == null) return NullMod.INSTANCE;
		if (v == null)
			return PrimMod.NULL;
		else
			return mod.getInverse(v);
	}

	public static void applyMods(Object[] vals, Mod[] result)
	{
		for (int i = 0; i < result.length; i++) {
			vals[i] = result[i].inPlaceApply(vals[i]);
		}
	}

}
